#include "Scene.h"

void Scene::Initialise(HWND *lwnd, Input *in)
{
	hwnd = lwnd;	// access to the window
	myInput = in;	// access to user input

	ticker = 0;	// used for moving object
	numPhysicsObjects = 10;

	// create our sprite, passing a filename for image to load, and starting location
	//Animated sprite needs width and hieght of frrame and two floats for timeings
	backgroundSkySprite.Initialise(&backHDC, "sky.bmp", 0, 0, 1, 1, 0, 0, false);
	backgroundGroundSprite.Initialise(&backHDC, "grass.bmp", 0, 592, 13, 1, 5000, 0.5, false);

	slingshotSprite.Initialise(&backHDC, "SlingshotSprite.bmp", 150, 455, 160, 292, 0.5, 0.5, 0, 0, myInput);	
	projectileSprite.Initialise(&backHDC, "RedBirdSprite.bmp", 150, 455, 564, 546, 0.1, 0.1, 0, 0, 10, 0.5, true);

	
	//Structure - building blocks for houses, walls etc. - Stuart

	//use animated sprite initialise//
	//House 1
	structureSprite[0].Initialise(&backHDC, "woodVertical.bmp", 670, 505, 16, 16, 2, 6, 0, 0, 15, 0.6, false);		// Left wall
	structureSprite[1].Initialise(&backHDC, "woodVertical.bmp", 766, 505, 16, 16, 2, 6, 0, 0, 15, 0.6, false);		// Right wall
	structureSprite[2].Initialise(&backHDC, "woodHorizontal.bmp", 670, 473, 16, 16, 8, 2, 0, 0, 30, 0.6, false);	// Roof
	//End House 1

	//House 2
	structureSprite[3].Initialise(&backHDC, "woodVertical.bmp", 1370, 505, 16, 16, 2, 6, 0, 0, 15, 0.6, false);		// Left wall
	structureSprite[4].Initialise(&backHDC, "woodVertical.bmp", 1466, 505, 16, 16, 2, 6, 0, 0, 15, 0.6, false);		// Right wall
	structureSprite[5].Initialise(&backHDC, "woodHorizontal.bmp", 1370, 473, 16, 16, 8, 2, 0, 0, 30, 0.6, false);		// Roof
	//End House 2
	 
	structureSprite[6].Initialise(&backHDC, "woodVertical.bmp", 970, 409, 16, 16, 2, 12, 0, 0, 50, 0.6, false);		// Wall 1
	structureSprite[7].Initialise(&backHDC, "woodVertical.bmp", 1070, 345, 16, 16, 2, 16, 0, 0, 60, 0.6, false);		// Wall 2

	//End Structure

	//add rest of items to list
	PhysicsList[0] = new PhysicsObject (projectileSprite.getRigidBody());

	for (int i = 1; i < 10; i++)
	{
		PhysicsList[i] = new PhysicsObject (structureSprite[i - 2].getRigidBody());
	}

	// configure buffers, based on window device context
	setBuffers();
}

void Scene::resize(HWND *lwnd)
{
	hwnd = lwnd;
	setBuffers();
}

void Scene::setBuffers()
{
    // creates rect based on window client area
    GetClientRect(*hwnd, &screenRect); 
    // Initialises front buffer device context (window)
    frontHDC = GetDC(*hwnd);
    // sets up Back DC to be compatible with the front
    backHDC = CreateCompatibleDC(frontHDC);
    //creates bitmap compatible with the front buffer
    theOldFrontBitMap = CreateCompatibleBitmap(frontHDC, screenRect.right, screenRect.bottom); 
    // puts the bitmap onto the back buffer
    SelectObject(backHDC, theOldFrontBitMap); 
    // blank back buffer
    FillRect(backHDC, &screenRect, (HBRUSH)GetStockObject(0));
}

void Scene:: render(float deltaTime)
{	
	//add rest of items to list
	PhysicsList[0] = new PhysicsObject (backgroundGroundSprite.getRigidBody());
	PhysicsList[1] = new PhysicsObject (projectileSprite.getRigidBody());

	for (int i = 2; i < numPhysicsObjects; i++)
	{
		PhysicsList[i] = new PhysicsObject (structureSprite[i - 2].getRigidBody());
	}

	if (projectileSprite.RigidBody.Launched())
	{
		CollisionDetection();
		CalculatePhysics();
	}


	// send sprite to drawSprite function
	backgroundSkySprite.drawSprite();
	backgroundGroundSprite.drawSprite();
	
	//Structures

	//House 1
	for (int i = 0; i < 8; i++)
	{
		structureSprite[i].drawAnimaSprite();	
	}
	//End Structures


	slingshotSprite.drawAnimaSprite();
	projectileSprite.drawAnimaSprite();
	
	//animated sprite Update
	if (!slingshotSprite.getFired())
	{
		slingshotSprite.Update();
		if (slingshotSprite.isMouseClicked())
		{
			projectileSprite.RigidBody.setX(slingshotSprite.getMouseX());
			projectileSprite.RigidBody.setY(slingshotSprite.getMouseY());
		}
	}
	else
	{
		if (!projectileSprite.RigidBody.Launched())
		{
			projectileSprite.RigidBody.Launch();
		}
		else
		{
			projectileSprite.RigidBody.ProjectileUpdate(deltaTime);
			for (int i = 2; i < numPhysicsObjects; i++)
			{
				structureSprite[i - 2].setRigidBody(*PhysicsList[i]);
				if (structureSprite[i - 2].RigidBody.Launched())
				{
					structureSprite[i - 2].RigidBody.ProjectileUpdate(deltaTime);
				}
			}
		}
	}

	projectileSprite.setSpriteX(projectileSprite.RigidBody.getX());
	projectileSprite.setSpriteY(projectileSprite.RigidBody.getY());
	
	for (int i = 2; i < numPhysicsObjects; i++)
	{
		if (structureSprite[i - 2].getRigidBody().getHit())
		{
			structureSprite[i - 2].RigidBody.setX(-1000);
			structureSprite[i - 2].RigidBody.setY(-1000);
		}
		structureSprite[i - 2].setSpriteX(structureSprite[i - 2].RigidBody.getX());
		structureSprite[i - 2].setSpriteY(structureSprite[i - 2].RigidBody.getY());
	}

	//finally push to front buffer (screen)
	displayFrame();
}

void Scene::displayFrame()
{
    BitBlt(frontHDC, screenRect.left,screenRect.top, screenRect.right, screenRect.bottom, backHDC, 0, 0, SRCCOPY);

    FillRect(backHDC, &screenRect, (HBRUSH)GetStockObject(0));
}

void Scene::shutdown()
{
    SelectObject(backHDC,theOldFrontBitMap);
    DeleteDC(backHDC);
    ReleaseDC(*hwnd,frontHDC);
}

BOOL Scene::WaitFor(unsigned long delay)
{
	static unsigned long clockStart = 0;
	unsigned long timePassed;
	unsigned long now = timeGetTime();

	timePassed = now - clockStart;
	if (timePassed >  delay)
	{
		clockStart = now;
		return TRUE;
	}
	else
		return FALSE;
}

void Scene::CollisionDetection()
{
	for (int i = 1; i < numPhysicsObjects; i++)
	{
		if (PhysicsList[i]->getHit())
		{
			for (int j = 0; j < numPhysicsObjects; j++)
			{
				if (i != j)
				{
					if (PhysicsList[i]->isColliding(PhysicsList[j]))
					{
						PhysicsList[j]->setHit(true);
						PhysicsList[i]->setHitting(j, true);
						PhysicsList[j]->setHitting(i, true);
					}
				}
			}
		}

		if (projectileSprite.getSpriteY() + projectileSprite.RigidBody.getHeight() > screenRect.bottom-120 && projectileSprite.getSpriteX() > slingshotSprite.getSpriteX())
		{
			projectileSprite.setSpriteY((screenRect.bottom - 120) - projectileSprite.RigidBody.getHeight());
			projectileSprite.RigidBody.ToggleLaunched();
			projectileSprite.RigidBody.setVelocity(0);
			projectileSprite.RigidBody.setTheta(0);

		}

		if (projectileSprite.getSpriteX() + projectileSprite.RigidBody.getWidth() > screenRect.right)
		{
			projectileSprite.setSpriteY((screenRect.right) - projectileSprite.RigidBody.getWidth());
			projectileSprite.RigidBody.ToggleLaunched();
			projectileSprite.RigidBody.setVelocity(0);
			projectileSprite.RigidBody.setTheta(0);
		}
	}
}

void Scene::CalculatePhysics()
{
	for (int i = 1; i < numPhysicsObjects; i++)
	{
		if (PhysicsList[i]->getHit())
		{
			for (int j = 0; j < numPhysicsObjects; j++)
			{
				if (i != j)
				{
					if (PhysicsList[i]->getHitting(j))
					{
						//calculate velocities for both object after collision
						float v1 = ((PhysicsList[i]->getMass() - PhysicsList[j]->getMass()) / (PhysicsList[i]->getMass() + PhysicsList[j]->getMass())) 
							* PhysicsList[i]->getVelocity() * PhysicsList[j]->getVelocity();
						float v2 = ((2 * PhysicsList[i]->getMass()) / (PhysicsList[i]->getMass() + PhysicsList[j]->getMass())) * PhysicsList[i]->getVelocity() * PhysicsList[j]->getVelocity();

						PhysicsList[i]->setVelocity(v1);
						PhysicsList[i]->Fire();

						//calculate new angle of projection
						if (PhysicsList[i]->getTheta() == 0)
						{
							PhysicsList[i]->setTheta(PhysicsList[j]->getTheta() + (90));
							PhysicsList[j]->setTheta(PhysicsList[j]->getTheta() * PhysicsList[i]->getRestitution());
						}
						else
						{
							PhysicsList[i]->setTheta(PhysicsList[i]->getTheta() * PhysicsList[j]->getRestitution());							
							PhysicsList[j]->setTheta(PhysicsList[i]->getTheta() + (90));
						}
						
						if (j != 1)
						{
							PhysicsList[j]->setVelocity(v2);
							PhysicsList[j]->Fire();
						}

						PhysicsList[i]->setHitting(j, false);
						PhysicsList[j]->setHitting(i, false);
					}
				}
			}
		}
	}
}